#######################################################
# Example of a toaster FSDEVS model
# FSDEVS stands for Finite (states & events) and Stochastic behaviors 
#  in terms of state transitions, output, and time advance. 
# Author: moonho.hwang@gmail.com
#   Date: Oct.19.2011
#######################################################
from XSY.DEVS.FSDEVS import * 
from XSY.DEVS.CoupledDEVS import *
from XSY.Set.Interval import *
from XSY.DEVS.SimEngine import SimEngine
from XSY.DEVS.VeriEngine import VeriEngine

class Toaster(FSDEVS):
   '''an atomic FSDEVS for a toaster'''
   def __init__(m, n, parent=None):
      '''constructor'''
      FSDEVS.__init__(m, n, parent) 
      m.addInputPorts('?push', '?repair')
      m.addOutputPorts('!pop')

   def rv_delta_0(m):
      '''random initial state'''
      return DRV({'I':1})

   def rv_tau(m):
      '''random lifespan scheduling function'''
      if m.phase == 'T':
         return TInterval(20,30) # continuous random variable distributed uniformly 
      else:
         return DRV({float('inf'):1}) # discrete random variable

   def rv_delta_x(m, x):
      '''random external transition function'''
      if x.port == m.IP['?push'] and m.phase == 'I':
         return DRV({(True,'T'):.9, (True,'D'):.1})
      elif x.port == m.IP['?repair'] and m.phase == 'D':
         return DRV({(True,'I'):1})
      else:
         return DRV({(False,m.phase):1})
               
   def rv_delta_y(m):
      '''random output and internal transition function'''
      if m.phase == 'T':
         y = PortValue(m.OP["!pop"])
         return DRV({(y,'I'):1})
   
   def get_state(m):
      '''get the state'''
      return m.phase

   def set_state(m, s):
      '''set the state as s'''
      m.phase = s

def make_input_event(md):
   ''' a callback function for injection'''
   ipn = raw_input('?push, ?repair>')
   if ipn in md.IP:
      ip = md.IP[ipn]
      return md, PortValue(ip)
   else:
      return None # inject None into timer 

def runSimulation(md):
   engine = SimEngine(md1, make_input_event)

   #---- setting StepByStep and DES simulation only ----
   engine.StepByStep = True
   engine.sfactor = float('inf')
   #----------------------------------------------------
   engine.runInteractiveMenu()

def runVerification(md):
   X = [ PortValue(md.IP['?push']), PortValue(md.IP['?repair'])]
   VE = VeriEngine(md, X, None, None)
   VE.runtimeInteractiveMenu()

if __name__ == '__main__':
   print 'This example shows a toaster "ts1"'
   print 'which can get started toasting by injection of "?push"'

   md1 = Toaster("ts1") 

   c = True
   while c:
      s = raw_input('[s]im, [v]eri, e[x]it>')
      if s == 's' or s == 'sim': 
         runSimulation(md1)
      elif s == 'v' or s == 'veri':
         runVerification(md1)
      elif s == 'x' or s == 'exit':
         c = False
      else:
         print('%s is an invalid input!'%s)
      
   print "good bye~!" 
  
